#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "li_basic.h"

/// <summary>
/// return 0/1
/// </summary>
/// <param name="s"></param>
/// <param name="cmd"></param>
/// <returns></returns>
char str_startwith(const char *s, const char *cmd)
{
	int32_t i, n;
	n = strlen(cmd);

	if (strlen(s) < n)
		return 0;

	for (i = 0; i < n; i++)
		if (s[i] != cmd[i])
			return 0;

	return 1;
}
/// <summary>
/// return index+1
/// if not found return 0
/// </summary>
/// <param name="s"></param>
/// <param name="c"></param>
/// <returns></returns>
int32_t str_contains(const char *s, char c)
{
	int32_t i;
	for (i = 0; s[i] != '\0'; i++)
		if (s[i] == c)
			return i + 1;
	return 0;
}
/// <summary>
/// str_contains����������s���Ƿ���c���ַ�
/// </summary>
/// <param name="s">string</param>
/// <param name="c">c in list</param>
/// <returns>0/1</returns>
int32_t str_contains_by_str(const char *s, char *c)
{
	int32_t i;
	for (i = 0; s[i] != '\0'; i++)
		if (str_contains(c, s[i]))
			return 1;
	// if (s[i] == c)return 1;
	return 0;
}

char str_equal(const char *s, const char *cmd)
{
	if (s[0] == '\0')
		return 0;

	int32_t i = 0;
	char a, b;
	do
	{
		a = s[i];
		b = cmd[i];
		i++;

		if (a != b)
			return 0;
	} while (s[i] != '\0' && cmd[i] != '\0' && cmd[i] != ':'); // the next char is not \0

	a = s[i];
	b = cmd[i];

	if (a == '\0') // b!=0, ahi = ahi[12]
	{
		if (isA(b) || isD(b) || b == '_')
			return 0;
		return i;
	}
	// b=='\0'
	if (isA(a) || isD(a) || a == '_')
		return 0;
	// if ('0' <= a && a <= '9')
	// 	return 0;
	return i;
}
/// <summary>
/// index c in s, only find once
/// return -1 if not found
/// else return the index in s
/// </summary>
/// <param name="s">string </param>
/// <param name="c">a char to fine</param>
/// <returns></returns>
int32_t str_index(const char *s, char c)
{
	if (!s)
		return -1;
	char *s2 = strchr(s, c);
	if (!s2)
		return -2;
	return s2 - s;
}
/// <summary>
/// �������������ַ�
/// </summary>
/// <param name="s"></param>
/// <param name="c"></param>
/// <returns>index or -1</returns>
int32_t str_index_right(char *s, char c)
{
	if (!s)
		return -1;
	char *s2 = strrchr(s, c);
	if (!s2)
		return -2;
	return s2 - s;
}
char str_lower(char *str)
{
	if (str == NULL)
		return 0;

	char *p = str;

	while (*p != '\0')
	{
		if (*p >= 'A' && *p <= 'Z')
			*p = (*p) + 0x20;

		p++;
	}

	return p - str;
}
/// <summary>
/// �ַ��滻
/// </summary>
/// <param name="s"></param>
/// <param name="from"></param>
/// <param name="to"></param>
/// <returns>counts</returns>
char str_replace(char *s, char from, char to)
{
	char times = 0;
	int32_t i;

	for (i = 0; s[i] != '\0'; i++)
	{
		if (s[i] == from)
		{
			s[i] = to;
			times++;
		}
	}

	return times;
}
char str_replace_by_str(char *s, const char *from, char to)
{
	char times = 0;
	int32_t i;

	for (i = 0; s[i] != '\0'; i++)
	{
		const char *p = from;
		while (*p != '\0')
		{
			if (*p == s[i])
			{
				s[i] = to;
				times++;
				break;
			}
			p++;
		}
	}

	return times;
}

/// <summary>
/// string replace, return a new string in heap
/// free it after using
/// </summary>
/// <param name="src"></param>
/// <param name="from"></param>
/// <param name="to"></param>
/// <returns>NULL if error</returns>
char *strReplace(const char *src, const char *from, const char *to)
{
	size_t size = strlen(src) + 1;
	size_t fromlen = strlen(from);
	size_t tolen = strlen(to);
	char *value = malloc(size);

	char *dst = value;
	if (value != NULL)
	{
		while (1)
		{
			const char *match = strstr(src, from);
			if (match != NULL)
			{
				size_t count = match - src;
				char *temp;
				size += tolen - fromlen;
				temp = realloc(value, size);
				if (temp == NULL)
				{
					free(value);

					return NULL;
				}
				dst = temp + (dst - value);
				value = temp;
				memmove(dst, src, count);
				src += count;
				dst += count;
				memmove(dst, to, tolen);
				src += fromlen;
				dst += tolen;
			}
			else /* No match found. */
			{
				strcpy(dst, src);
				break;
			}
		}
	}
	return value;
}

// '-123.45', '+13.890'
int32_t str_is_numeric(const char *name)
{
	if (!isD(*name) && *name != '+' && *name != '-')
		return 0;
	if (!isD(*name))
	{
		name++;
		if (*name == '\0')
			return 0;
	}
	else
		name++;

	char lastIsDecimal = 0;
	char hasDecimal = 0;
	for (; *name != '\0'; name++)
	{
		if (isD(*name))
		{
			lastIsDecimal = 0;
			continue;
		}
		else if (*name == '.')
		{
			hasDecimal++;
			if (lastIsDecimal || hasDecimal > 1)
				return 0;
			lastIsDecimal = 1;
			continue;
		}

		return 0;
	}
	return hasDecimal ? 1 : 2; // 1 for float, 2 for int
}
// a, _ah_haha_, _label_text3
int32_t str_is_name(const char *name)
{
	if (!isA(*name) && *name != '_')
		return 0;
	if (*name == '_')
	{
		name++;
		if (*name == '\0')
			return 0;
	}
	else
		name++;

	while (*name != '\0')
	{
		if (!isA(*name) && !isD(*name) && *name != '_')
			return 0;
		name++;
	}
	return 1;
}
// in place operation,
//  note: delete list returned in time
Li_List str_split(char *str, char split_char)
{
	Li_List list = new_list(sizeof(char *), 4);
	if (*str == '\0')
		return list;
	char *last; // , * next;
	char *now = str;
	if (*now != split_char)
	{
		list_add(list, &str);
	}
	last = now;
	now++;
	// next = now;
	while (*now != '\0')
	{
		if (*last == split_char && *now != split_char)
		{
			li_add(list, now);
			/**last = '\0';*/
		}
		if (*last != split_char && *now == split_char)
		{
			*now = '\0';
			last = &split_char;
			now++; // = next;
			// next++;
			continue;
		}

		last = now;
		now++; //= next;
			   // next++;
	}
	return list;
}
// in place operation,
//  note: delete list returned in time
Li_List str_split_by_str(char *str, const char *split_char)
{
	Li_List list = new_list(sizeof(char *), 4);
	if (*str == '\0')
		return list;
	char *last; //, * next;
	char *now = str;
	if (!str_contains(split_char, *now))
	// if (*now != split_char)
	{
		list_add(list, &str);
	}
	last = now;
	now++;
	// next = now;
	while (*now != '\0')
	{
		if (str_contains(split_char, *last) && !str_contains(split_char, *now))
		// if (*last == split_char && *now != split_char)
		{
			li_add(list, now);
			/**last = '\0';*/
		}
		if (!str_contains(split_char, *last) && str_contains(split_char, *now))
		// if (*last != split_char && *now == split_char)
		{
			*now = '\0';
			last = split_char;
			now++; // = next;
			// next++;
			continue;
		}

		last = now;
		now++; //= next;
			   // next++;
	}
	return list;
}

/// # summary
/// note: delete list returned in time
/// find indexs of chars in find in string s
/// e.g. str_find("1+2*3/4", "+-*/")
/// return [1,3,5]
/// </summary>
/// <param name="s"></param>
/// <param name="find"></param>
/// <returns></returns>
Li_List str_find(char *s, const char *find)
{
	Li_List list = new_list(sizeof(int32_t), 4);
	if (list == NULL)
		return list;
	int32_t i;
	for (i = 0; s[i] != '\0'; i++)
	{
		if (str_contains(find, s[i]))
			li_add(list, i);
	}
	return list;
}
Li_List str_find_sort(char *s, const char *find)
{
	Li_List list = new_list(sizeof(int32_t), 4);
	if (list == NULL)
		return list;
	int32_t i;
	for (i = 0; find[i] != '\0'; i++)
	{
		int32_t j;
		for (j = 0; s[j] != '\0'; j++)
			if (s[j] == find[i])
				li_add(list, j);
	}
	return list;
}

/// <summary>
/// string find count
/// </summary>
/// <param name="str1"></param>
/// <param name="str2"></param>
/// <returns>NULL if count=0</returns>
Li_List str_count(char *str1, const char *str2)
{
	int32_t i, j;
	// int32_t count = 0;
	i = j = 0;
	if (str2 == NULL)
		return NULL;
	int32_t dlen = strlen(str2);
	Li_List list = new_list(sizeof(int32_t), 4);
	while (str1[i] != '\0')
	{
		while (str1[i] != '\0' && str2[j] != '\0')
		{
			if (str1[i] == str2[j])
			{
				i++;
				j++;
			}
			else
			{
				i = i - j + 1;
				j = 0;
			}
		}
		if (str2[j] == '\0')
		{
			// count++;
			int32_t ind = i - dlen;
			li_add(list, ind);
			j = 0;
		}
	}

	if (!list->count)
	{
		delete_list(list);
		return NULL;
	}
	return list;
}

/// <summary>
/// like str_count(), but only the number is returned
/// </summary>
/// <param name="str1"></param>
/// <param name="str2"></param>
/// <returns></returns>
int32_t str_count_n(const char *str1, const char *str2)
{
	int32_t i, j;
	int32_t count = 0;
	i = j = 0;
	if (str1 == NULL || str2 == NULL)
		return 0;
	while (str1[i] != '\0')
	{
		while (str1[i] != '\0' && str2[j] != '\0')
		{
			if (str1[i] == str2[j])
			{
				i++;
				j++;
			}
			else
			{
				i = i - j + 1;
				j = 0;
			}
		}
		if (str2[j] == '\0')
		{
			count++;
			/*int32_t ind = i - dlen;
			li_add(list, ind);*/
			j = 0;
		}
	}

	return count;
}

// add the num to a string
// return: length of num
char int_to_string(int32_t n, char *s)
{
	if (n == 0)
	{
		s[0] = '0';
		return 1;
	}
	char add = 0;

	if (n < 0)
	{
		n *= -1;
		s[0] = '-';
		s++;
		add = 1;
	}
	int32_t i;
	for (i = 0; n > 0; i++, n /= 10)
	{
		s[i] = n % 10 + '0';
	}
	int32_t j;
	char a;
	for (j = 0; j < i / 2; j++)
	{
		a = s[j];
		s[j] = s[i - j - 1];
		s[i - j - 1] = a;
	}
	s[i + add] = '\0';
	return i + add;
}

float str_to_float(char *s)
{
	int32_t integer = 0;
	float decimal = 0.0f;
	float kd = 0.1f;
	int32_t in_decimal = 0;
	char is_neg = 0;
	if (*s == '-')
	{
		is_neg = 1;
		s++;
	}
	else if (*s == '+')
	{
		s++;
	}
	for (; *s != '\0'; s++)
	{
		if (*s == '.')
		{
			in_decimal = 1;
			continue;
		}
		if (!isD(*s))
			return 0.0f;
		if (in_decimal)
		{
			float d = *s - '0';

			decimal += d * kd;
			kd /= 10.0f;
		}
		else
		{
			int32_t d = *s - '0';
			integer *= 10;
			integer += d;
		}
	}
	if (is_neg)
	{
		return -(integer + decimal);
	}
	else
		return (integer + decimal);
}
// s[at]=c
void str_insert_at(char *s, char c, int32_t at)
{
	int32_t i = strlen(s) + 1;
	while (i > at)
	{
		s[i] = s[i - 1];
		i--;
	}
	s[i] = c;
}

float *get_nums_from_rx(char *rs, int32_t *length_back)
{
	static float nums[10];
	int32_t i, k = 0;
	float j = 10.0f;
	char negative = 0;
	j = 10.0f;
	char has_decimal = 0;
	float integer = 0.0f, decimal = 0.0f;
	char c;
	char last_is_numeric = 0;
	for (i = 0; rs[i] != '\0'; i++)
	{
		c = rs[i];
		if ('0' <= c && c <= '9') // number
		{
			if (!last_is_numeric) // at the begin
			{
				integer = (c - '0');
				decimal = 0;
				has_decimal = 0;
				j = 10;
			}
			else if (has_decimal) // go on
			{
				decimal += (float)(c - '0') / j;
				j *= 10.0f;
			}
			else
			{
				integer *= 10.0f;
				integer += (c - '0');
			}
			last_is_numeric = 1;
			continue;
		}
		// not numeric
		else if (c == '.' && last_is_numeric) // xxx.
		{
			has_decimal = 1;
			last_is_numeric = 1;
			continue;
		}
		else if (c == '-') // -
		{
			negative = !negative; // clear in end
		}
		else if (last_is_numeric) // end
		{
			nums[k] = decimal + integer;
			if (negative)
			{
				nums[k] *= -1;
				negative = 0;
			}
			k++;
		}
		last_is_numeric = 0;
	}

	if (last_is_numeric) // end
	{
		nums[k] = decimal + integer;
		if (negative)
			nums[k] *= -1;
		k++;
	}

	if (k == 0)
	{
		*length_back = 0;
		return nums;
	}

	*length_back = k;
	return nums;
}

// assert a word starts with a letter a-z
char **get_paras_from_rx(char *rx, int32_t *len)
{
	static char s[5][8]; // 5 rows, 7 chars a string maximum
	static char *p[5];
	int32_t i, j;
	char is_last_a_letter;
	for (i = 0; i < 5; i++)
		p[i] = s[i];
	i = 0;
	// while (*rx != '\0')//skip the cmd
	//{
	//	if (*rx < 'a' || *rx>'z')//not a letter
	//		break;
	//	rx++;
	// }
	while (*rx != '\0') // skip the cmd
	{
		if ('a' <= *rx && *rx <= 'z') // a letter
			break;
		rx++;
	}

	if (*rx == '\0')
	{
		*len = 0;
		return p;
	}
	i = 0;
	j = 0;
	is_last_a_letter = 0;
	while (*rx != '\0')
	{
		if ('a' <= *rx && *rx <= 'z' || *rx == '_') // a letter
		{
			if (!is_last_a_letter) // begin
			{
				j = 0;
			}
			// go on
			s[i][j++] = *rx;
			is_last_a_letter = 1;
			rx++;
			continue;
		}
		else if (is_last_a_letter) // end
		{
			s[i][j] = '\0';
			i++;
		}
		rx++;
		is_last_a_letter = 0;
	}

	s[i][j] = '\0';
	if (is_last_a_letter) // end
	{
		i++;
	}
	*len = i;
	return p;
}

void limit_to(float *x, float max)
{
	if (*x > max)
		*x = max;
	else if (*x < -max)
		*x = -max;
}
void limit_from_to(float *x, float lower, float upper)
{
	if (*x < lower)
		*x = lower;
	else if (*x > upper)
		*x = upper;
}

int32_t str_wrap(char *s, char c)
{
	char *pStr = s;
	char *pTmp = pStr;

	while (*pStr != '\0')
	{
		if (*pStr != c)
		{
			*pTmp++ = *pStr;
		}
		++pStr;
	}
	*pTmp = '\0';
	return pTmp - s;
}

int32_t str_wrap_by_str(char *s, const char *cs)
{
	int32_t i, j = 0;
	while (*cs != '\0')
	{
		i = 0;
		j = 0;
		while (1)
		{
			if (s[i] != *cs && s[i] != '\0')
				s[j++] = s[i++];
			else if (s[i++] == '\0')
			{
				s[j] = '\0';
				break;
			}
		}
		cs++;
	}
	return j;
}
// find first the not-char in a string, to remove blank
// s += str_left_wrap(s,c);
int32_t str_left_wrap(char *s, char c)
{
	int32_t i = 0;
	while (s[i] == c)
	{
		i++;
	}
	return i;
}
/// <summary>
/// ƴ���ַ�������̬�����ڴ�
/// ��Ҫstr�ڶ���
/// in heap, using malloc
/// s = dynamic_str_cat(s,"more");
/// </summary>
/// <param name="str">a string in heap</param>
/// <param name="sub">sub will append to str</param>
/// <returns>null if error, new string otherwise</returns>
char *dynamic_str_cat(char *str, const char *sub)
{
	int32_t n = strlen(str);
	int32_t m = strlen(sub);
	if (!m)
		return str;

	void *p = realloc(str, m + n + 1);
	if (!p)
		return p;
	if (str == p)
	{
		memcpy(str + n, sub, m + 1);
		return p;
	}
	if (sub == str)
	{
		sub = p;
	}
	memcpy((char *)p + n, sub, m);
	((char *)p)[m + n] = 0;
	// p = malloc(m + n + 1);
	// if (p == NULL)
	//{
	//	return NULL;
	// }
	// memmove(p, str, n);
	// memcpy((char*)p + n, sub, m + 1);
	// free(str);
	return p;
}

int str_translate(const char *_str, char *out)
{
	int state = 0;
	char *s = _str;
	char c = *s;
	char *p = out;
	int _ln;
	while (c)
	{
		switch (state)
		{
		case 0:
			if (c == '\'')
			{
				state = 2;
			}
			else if (c == '\"')
			{
				state = 3;
			}
			else
			{
				*p++ = c;
			}
			break;
		case 1:
			if (c == 'n')
				*p++ = '\n';
			else if (c == 'r')
				*p++ = '\r';
			else if (c == '\\')
				*p++ = '\\';
			else if (c == '\'')
				*p++ = '\'';
			else if (c == '\"')
				*p++ = '\"';
			else if (c == 't')
				*p++ = '\t';
			else if (c == 'a')
				*p++ = '\a';
			else if (c == 'b')
				*p++ = '\b';
			else if (c == 'v')
				*p++ = '\v';
			else if (c == 'f')
				*p++ = '\f';
			else
			{
				*p++ = '\\';
				*p++ = c;
				// or error
			}
			state = _ln;
			break;
		case 2:
			if (c == '\\')
			{
				_ln = state;
				state = 1;
			}
			else if (c == '\'')
			{
				state = 0;
			}
			else
			{
				*p++ = c;
			}
			break;
		case 3:
			if (c == '\\')
			{
				_ln = state;
				state = 1;
			}
			else if (c == '\"')
			{
				state = 0;
			}
			else
			{
				*p++ = c;
			}
			break;
		default:
			return -1;
		}
		c = *(++s);
	}
	*p++ = '\0';
	if (state)
	{
		return -2;
	}
	return p - out;
}
int str_translate2(const char *_str, char *out)
{
	int state = 0;
	char *s = _str;
	char c = *s;
	char *p = out;
	int _ln;
	while (c)
	{
		switch (state)
		{
		case 0:
			if (c == '\'')
			{
				state = 2;
			}
			else if (c == '\"')
			{
				state = 3;
			}
			else
			{
				*p++ = '\0';
				return p - out;
			}
			break;
		case 1:
			if (c == 'n')
				*p++ = '\n';
			else if (c == 'r')
				*p++ = '\r';
			else if (c == '\\')
				*p++ = '\\';
			else if (c == '\'')
				*p++ = '\'';
			else if (c == '\"')
				*p++ = '\"';
			else if (c == 't')
				*p++ = '\t';
			else if (c == 'a')
				*p++ = '\a';
			else if (c == 'b')
				*p++ = '\b';
			else if (c == 'v')
				*p++ = '\v';
			else if (c == 'f')
				*p++ = '\f';
			else
			{
				*p++ = '\\';
				*p++ = c;
				// or error
			}
			state = _ln;
			break;
		case 2:
			if (c == '\\')
			{
				_ln = state;
				state = 1;
			}
			else if (c == '\'')
			{
				state = 0;
			}
			else
			{
				*p++ = c;
			}
			break;
		case 3:
			if (c == '\\')
			{
				_ln = state;
				state = 1;
			}
			else if (c == '\"')
			{
				state = 0;
			}
			else
			{
				*p++ = c;
			}
			break;
		default:
			return -1;
		}
		c = *(++s);
	}
	*p++ = '\0';
	if (state)
	{
		return -2;
	}
	return p - out;
}
int str_translate2_r(const char *_str, char *out)
{
	int state = 0;
	char *s = _str;
	char c = *s;
	char *p = out;
	int _ln;
	while (c)
	{
		switch (state)
		{
		case 0:
			if (c == '\'')
			{
				state = 2;
			}
			else if (c == '\"')
			{
				state = 3;
			}
			else
			{
				*p++ = '\0';
				return p - out;
			}
			break;
		case 1:
			if (_ln == 2 && c == '\'')
				*p++ = '\'';
			else if (_ln == 3 && c == '\"')
				*p++ = '\"';
			else
			{
				*p++ = '\\';
				*p++ = c;
			}
			state = _ln;
			break;
		case 2:
			if (c == '\\')
			{
				_ln = state;
				state = 1;
			}
			else if (c == '\'')
			{
				state = 0;
			}
			else
			{
				*p++ = c;
			}
			break;
		case 3:
			if (c == '\\')
			{
				_ln = state;
				state = 1;
			}
			else if (c == '\"')
			{
				state = 0;
			}
			else
			{
				*p++ = c;
			}
			break;
		default:
			return -1;
		}
		c = *(++s);
	}
	*p++ = '\0';
	if (state)
	{
		return -2;
	}
	return p - out;
}

int str_translate_get_len(const char *_str, int * out_raw_len)
{
	int state = 0;
	char *s = _str;
	char c = *s;
	int _ln;
	int len = 0;
	while (c)
	{
		switch (state)
		{
		case 0:
			if (c == '\'')
			{
				state = 2;
			}
			else if (c == '\"')
			{
				state = 3;
			}
			else
			{
				len++;
				*out_raw_len = s - _str;
				return len;
			}
			break;
		case 1:
			if (c == 'n')
				len++;
			else if (c == 'r')
				len++;
			else if (c == '\\')
				len++;
			else if (c == '\'')
				len++;
			else if (c == '\"')
				len++;
			else if (c == 't')
				len++;
			else if (c == 'a')
				len++;
			else if (c == 'b')
				len++;
			else if (c == 'v')
				len++;
			else if (c == 'f')
				len++;
			else
			{
				len++;
				len++;
				// or error
			}
			state = _ln;
			break;
		case 2:
			if (c == '\\')
			{
				_ln = state;
				state = 1;
			}
			else if (c == '\'')
			{
				state = 0;
			}
			else
			{
				len++;
			}
			break;
		case 3:
			if (c == '\\')
			{
				_ln = state;
				state = 1;
			}
			else if (c == '\"')
			{
				state = 0;
			}
			else
			{
				len++;
			}
			break;
		default:
			return -1;
		}
		c = *(++s);
	}
	len++;
	if (state)
	{
		return -2;
	}
	*out_raw_len = s - _str;
	return len;
}

int str_translate_get_len_r(const char *_str, int*out_raw_len)
{
	int state = 0;
	char *s = _str;
	char c = *s;
	int _ln;
	int len = 0;
	while (c)
	{
		switch (state)
		{
		case 0:
			if (c == '\'')
			{
				state = 2;
			}
			else if (c == '\"')
			{
				state = 3;
			}
			else
			{
				len++;
				*out_raw_len = s - _str;
				return len;
			}
			break;
		case 1:
			if (_ln == 2 && c == '\'')
				len++;
			else if (_ln == 3 && c == '\"')
				len++;
			else
			{
				len += 2;
			}
			state = _ln;
			break;
		case 2:
			if (c == '\\')
			{
				_ln = state;
				state = 1;
			}
			else if (c == '\'')
			{
				state = 0;
			}
			else
			{
				len++;
			}
			break;
		case 3:
			if (c == '\\')
			{
				_ln = state;
				state = 1;
			}
			else if (c == '\"')
			{
				state = 0;
			}
			else
			{
				len++;
			}
			break;
		default:
			return -1;
		}
		c = *(++s);
	}
	len++;
	if (state)
	{
		return -2;
	}
	*out_raw_len = s - _str;
	return len;
}

Li_List str_cmd_split(char *_str)
{
	char *s = _str;
	Li_List list = new_li(char *);
	char c = *s;
	char *p = s;
	char *q = s;
	int state = 0;
	char lr = 0;
	while (c)
	{
		switch (state)
		{
		case 0:
			if (c == ' ' || c == '\t')
			{
				state = 1;
				*p++ = 0;
				li_add(list, q);
				break;
			}
			if (c == '\'' || c == '\"')
			{
				state = 2;
				lr = c;
				break;
			}
			*p++ = c;
			break;
		case 1:
			if (c != ' ' && c != '\t')
			{
				state = 0;
				q = p;
				s--;
			}
			break;
		case 2:
			if (c == lr)
			{
				state = 0;
				*p = 0;
			}
			else if (c == '\\')
			{
				state = 3;
			}
			else
			{
				*p++ = c;
			}
			break;
		case 3:
			if (c == 'n')
				*p++ = '\n';
			else if (c == 'r')
				*p++ = '\r';
			else if (c == '\\')
				*p++ = '\\';
			else if (c == '\'')
				*p++ = '\'';
			else if (c == '\"')
				*p++ = '\"';
			else if (c == 't')
				*p++ = '\t';
			else if (c == 'a')
				*p++ = '\a';
			else if (c == 'b')
				*p++ = '\b';
			else if (c == 'v')
				*p++ = '\v';
			else if (c == 'f')
				*p++ = '\f';
			else
			{
				*p++ = '\\';
				*p++ = c;
			}
			state = 2;
			break;
		default:
			break;
		}
		c = *(++s);
	}

	if (state == 0)
	{
		li_add(list, q);
		return list;
	}
	if (state == 1)
	{
		return list;
	}
	delete_list(list);
	return NULL;
}